
#ifndef GMACHINE_HEADER_GUTILITY_H
#define	GMACHINE_HEADER_GUTILITY_H

namespace GMachine
{
	//template<bool> struct CompileTimeAssert {};
	//template<> struct CompileTimeAssert<false> { int MakeError[0]; };

//	class ByteOrder {
//		public: enum { LITTLEENDING, BIGENDING };
//		public:	enum { Value = (0x01020304 == '\x04\x03\x02\x01' ? LITTLEENDING : BIGENDING) };
//	};

    template <typename T, typename U, bool>
	struct SelectFirst
	{
		typedef typename T Class;
	};

	template <typename T, typename U>
	struct SelectFirst<T, U, false>
	{
		typedef typename U Class;
	};
	
	template<typename T> class TypeTraits {
	public:
		template<typename V> struct Reduce { 
			typedef V Class; 
			enum { IsPointer = 0, IsReference = 0, IsConst = 0, IsVolatile = 0 };
		};
		template<typename V> struct Reduce <volatile V> { 
			typedef V Class;
			enum { IsPointer = 0, IsReference = 0, IsConst = 0, IsVolatile = 1 };
		};
		template<typename V> struct Reduce <const V> { 
			typedef V Class;
			enum { IsPointer = 0, IsReference = 0, IsConst = 1, IsVolatile = 0 };
		};		
		template<typename V> struct Reduce <const volatile V> {
			typedef V Class;
			enum { IsPointer = 0, IsReference = 0, IsConst = 1, IsVolatile = 1 };
		};
		template<typename V> struct Reduce <V &> { 
			typedef V Class;
			enum { IsPointer = 0, IsReference = 1, IsConst = 0, IsVolatile = 0 };
		};
		template<typename V> struct Reduce <volatile V &> { 
			typedef V Class;
			enum { IsPointer = 0, IsReference = 1, IsConst = 0, IsVolatile = 1 };
		};
		template<typename V> struct Reduce <const V &> {
			typedef V Class;
			enum { IsPointer = 0, IsReference = 1, IsConst = 1, IsVolatile = 0 };
		};		
		template<typename V> struct Reduce <const volatile V &> {
			typedef V Class;
			enum { IsPointer = 0, IsReference = 1, IsConst = 1, IsVolatile = 1 };
		};
		template<typename V> struct Reduce <V *> {
			typedef V Class;
			enum { IsPointer = 1, IsReference = 0, IsConst = 0, IsVolatile = 0 };
		};
		template<typename V> struct Reduce <volatile V *> {
			typedef V Class;
			enum { IsPointer = 1, IsReference = 0, IsConst = 0, IsVolatile = 1 };
		};
		template<typename V> struct Reduce <const V *> {
			typedef V Class;
			enum { IsPointer = 1, IsReference = 0, IsConst = 1, IsVolatile = 0 };
		};		
		template<typename V> struct Reduce <const volatile V *> {
			typedef V Class;
			enum { IsPointer = 1, IsReference = 0, IsConst = 1, IsVolatile = 1 };
		};
		// Model class
		template<typename K, unsigned int> struct DefineModelClass;
		template<typename K> struct DefineModelClass<K, 0> { typedef typename TypeTraits<K>::Class					Result; };
		template<typename K> struct DefineModelClass<K, 1> { typedef typename TypeTraits<K>::ConstClass				Result; };
		template<typename K> struct DefineModelClass<K, 2> { typedef typename TypeTraits<K>::VolatileClass			Result; };
		template<typename K> struct DefineModelClass<K, 3> { typedef typename TypeTraits<K>::ConstVolatileClass		Result; };
		template<typename K> struct DefineModelClass<K, 4> { typedef typename TypeTraits<K>::Pointer				Result; };
		template<typename K> struct DefineModelClass<K, 5> { typedef typename TypeTraits<K>::ConstPointer			Result; };
		template<typename K> struct DefineModelClass<K, 6> { typedef typename TypeTraits<K>::VolatilePointer		Result; };
		template<typename K> struct DefineModelClass<K, 7> { typedef typename TypeTraits<K>::ConstVolatilePointer	Result; };
		template<typename K> struct DefineModelClass<K, 8> { typedef typename TypeTraits<K>::Reference				Result; };
		template<typename K> struct DefineModelClass<K, 9> { typedef typename TypeTraits<K>::ConstReference			Result; };
		template<typename K> struct DefineModelClass<K,10> { typedef typename TypeTraits<K>::VolatileReference		Result; };
		template<typename K> struct DefineModelClass<K,11> { typedef typename TypeTraits<K>::ConstVolatileReference Result; };

	public:
		enum { 
			IsReference	= Reduce<T>::IsReference,
			IsPointer	= Reduce<T>::IsPointer,
			IsVolatile	= Reduce<T>::IsVolatile,
			IsConst		= Reduce<T>::IsConst,
			ModelId		= (Reduce<T>::IsReference	? 8:0)
						+ (Reduce<T>::IsPointer		? 4:0)
						+ (Reduce<T>::IsVolatile	? 2:0)
						+ (Reduce<T>::IsConst		? 1:0)
		};

		typedef typename Reduce<T>::Class							Class;
		typedef const Class											ConstClass;
		typedef volatile Class										VolatileClass;
		typedef const volatile Class								ConstVolatileClass;
		typedef Class *												Pointer;
		typedef ConstClass *										ConstPointer;
		typedef VolatileClass *										VolatilePointer;
		typedef ConstVolatileClass *								ConstVolatilePointer;
		typedef Class &												Reference;
		typedef ConstClass &										ConstReference;
		typedef VolatileClass &										VolatileReference;
		typedef ConstVolatileClass &								ConstVolatileReference;
		typedef typename SelectFirst<
            Class, TypeTraits<U>::NativeClass, (ModelId != 0)
            >::Class                                                NativeClass;

		// BUG:
		//template<typename K, unsigned int model = TypeTraits<T>::ModelId> struct ReplaceName {
		//	typedef typename DefineModelClass<typename TypeTraits<Class>::ReplaceName<K>::Result, ModelId>::Result Result;
		//};
		//template<typename K> struct ReplaceName<K, 0> { typedef typename K Result; };
		//-----------------------------------------------
	};
	

	namespace Conversion {
		enum { NONE, SAME, FORWARD, BACKWARD, DUAL };
		// Conversion::Check<type1, type2>
		template<typename U, typename V> class Check {
		//-----------------------------------------------
			template<typename A, typename B> class Digger {
				typedef char (&Yes)[1];	typedef char (&No)[2];
				static Yes Catcher(B); static No Catcher(...); static A Faker();
			public: enum { Found = (sizeof(Catcher(Faker())) == sizeof(Yes)) };
			};
			template<typename A> class Digger<A, void> { public: enum { Found = false }; };
			template<typename B> class Digger<void, B> { public: enum { Found = false }; };
			template<typename A> class Digger<A, const void> { public: enum { Found = false }; };
			template<typename B> class Digger<const void, B> { public: enum { Found = false }; };
			template<typename A> class Digger<A, volatile void> { public: enum { Found = false }; };
			template<typename B> class Digger<volatile void, B> { public: enum { Found = false }; };
			template<typename A> class Digger<A, const volatile void> { public: enum { Found = false }; };
			template<typename B> class Digger<const volatile void, B> { public: enum { Found = false }; };
			template<> class Digger<void, const void> { public: enum { Found = true }; };
			template<> class Digger<void, volatile void> { public: enum { Found = true }; };
			template<> class Digger<void, const volatile void> { public: enum { Found = true }; };
			template<> class Digger<const void, void> { public: enum { Found = true }; };
			template<> class Digger<const void, volatile void> { public: enum { Found = true }; };
			template<> class Digger<const void, const volatile void> { public: enum { Found = true }; };
			template<> class Digger<volatile void, void> { public: enum { Found = true }; };
			template<> class Digger<volatile void, const void> { public: enum { Found = true }; };
			template<> class Digger<volatile void, const volatile void> { public: enum { Found = true }; };
			template<> class Digger<const volatile void, void> { public: enum { Found = true }; };
			template<> class Digger<const volatile void, const void> { public: enum { Found = true }; };
			template<> class Digger<const volatile void, volatile void> { public: enum { Found = true }; };
			template<typename M, typename N> struct Resolver {
				enum { Result = Digger<M, N>::Found ? (Digger<N, M>::Found ? DUAL:FORWARD):(Digger<N, M>::Found ? BACKWARD:NONE)};
			};
			template<typename M> struct Resolver<M, M> {
				enum { Result = SAME };
			};
		public:	
			// 'Model' is the one of { SAME, DUAL, FORWARD, BACKWARD, NONE }
			// 'Exist' is a boolean value, it's set if the conversation exists which from first to second.
			enum { 
				Model = Resolver<U, V>::Result, 
				Exist = ((Resolver<U, V>::Result != BACKWARD) && (Resolver<U, V>::Result != NONE)) 
			};
			//-----------------------------------------------
		};
	};


}

#endif	//ifndef GMACHINE_HEADER_GUTILITY_H

